package com.doyoulike.service.table;

import cn.hutool.core.collection.CollectionUtil;
import com.doyoulike.config.gen.GenConfig;
import com.doyoulike.dao.business.GenDataBaseDao;
import com.doyoulike.dao.primary.GenTableChildDao;
import com.doyoulike.dao.primary.GenTableColumnDao;
import com.doyoulike.dao.primary.GenTableDao;
import com.doyoulike.entity.DataBaseColumn;
import com.doyoulike.entity.GenTable;
import com.doyoulike.entity.GenTableColumn;
import com.doyoulike.enums.GenTypeEnum;
import com.doyoulike.service.gen.CodeGenService;
import com.doyoulike.util.ColumnUtil;
import com.doyoulike.util.SnowFlake;
import com.doyoulike.vo.in.CreateByIdsVO;
import com.doyoulike.vo.in.DelByGenTableNameVO;
import com.doyoulike.vo.in.ImportTableVO;
import com.doyoulike.vo.in.PageGenTableVO;
import com.doyoulike.vo.out.GeneratedContent;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.zip.ZipOutputStream;

/**
 * 表 Service
 * @author 独舟
 * @version 2020-03-20
 */
@Service
public class GenTableService {

	@Autowired
	private SnowFlake snowFlake;
	@Autowired
	private GenTableDao genTableDao;
	@Autowired
	private GenTableColumnDao genTableColumnDao;
	@Autowired
	private GenConfig genConfig;
	@Autowired
	private GenTableChildDao genTableChildDao;
	@Autowired
	private GenDataBaseDao genDataBaseDao;
	@Autowired
	private CodeGenService codeGenService;

	/**
	 * 导入表
	 */
	@Transactional(rollbackFor = Exception.class)
	public void importTable(ImportTableVO importTableVO) {
		genTableDao.deleteByNameList(importTableVO.getNames());
		genTableColumnDao.deleteByGenTableNameList(importTableVO.getNames());
		List<GenTable> genTables = genDataBaseDao.findTableListByNames(importTableVO.getNames());
		for (GenTable genTable : genTables) {
			String className = ColumnUtil.toCapitalizeCamelCase(genTable.getName());
			String chName = genTable.getRemarks().replace("表", "");
			genTable.setId(snowFlake.nextId());				    // id
			genTable.setClassName(className);                   // 类名
			genTable.setChName(chName); 					    // 类中文名
			genTable.setPackagePath(genConfig.getPackagePath());// 包路径
			genTable.setModuleName(genConfig.getModule());      // 模块名
			genTable.setSubModuleName(genConfig.getSubModule());// 子模块名
			genTable.setFunctionAuthor(genConfig.getAuth());    // 功能作者
			genTable.setGenTypeCode(GenTypeEnum.单表.getKey());  // 生成方式
			genTable.setRemarks("");                            // 备注
			genTable.setCreateDate(new Date());                 // 创建日期
			genTable.setUpdateDate(new Date());                 // 更新日期
			genTable.setColumnList(getGenTableColumns(genTable.getName())); // 表的列
			genTableDao.insert(genTable);
			genTableColumnDao.inserts(genTable.getColumnList());
		}
	}

	/**
	 * 导入-组装列数据
	 */
	private List<GenTableColumn> getGenTableColumns(String tableName) {
		List<DataBaseColumn> tableColumnList = genDataBaseDao.findTableColumnList(tableName);
		List<GenTableColumn> result = new ArrayList<>();
		int sort = 0;
		ColumnUtil.initColumn(tableColumnList);
		for (DataBaseColumn column : tableColumnList) {
			GenTableColumn tableColumn = new GenTableColumn();
			tableColumn.setGenTableName(tableName); // 所属表名称
			tableColumn.setName(column.getName()); // 列名
			tableColumn.setComments(column.getComments()); // 列注释
			tableColumn.setIsPk(column.getIsPk()); // 是否主键（1：主键）
			tableColumn.setJdbcType(column.getJdbcType()); // JDBC类型（大写）
			tableColumn.setColumnType(column.getColumnType()); // 列类型（JDBC类型+长度）
			tableColumn.setValueLength(column.getIntMaxLength()); // 长度
			tableColumn.setIntAccuracy(column.getIntAccuracy()); // 整数精度（小数点多少位）
			tableColumn.setJavaType(column.getJavaType()); // JAVA类型
			tableColumn.setJavaField(column.getJavaField()); // JAVA字段名
			// tableColumn.setIsNull(column.getIsNull()); // 是否可为空（1：可为空；0：不为空）
			tableColumn.setIsNull(1); // 是否可为空（1：可为空；0：不为空）
			tableColumn.setIsQuery(0); // 是否查询字段（1:是、0:否）
			tableColumn.setIsAdd(1); // 是否添加（1:是、0:否）
			if(ColumnUtil.isAddExcludeField(column.getName())) tableColumn.setIsAdd(0); // 如果是添加时排除的字段则设置为否
			tableColumn.setIsUpdate(1); // 是否更新（1:是、0:否）
			if(ColumnUtil.isEditExcludeField(column.getName())) tableColumn.setIsUpdate(0); // 如果是更新时排除的字段则设置为否
			tableColumn.setUiElement("文本框"); // TODO 前端UI元素
			tableColumn.setQueryType(""); // 查询方式（等于、不等于、大于、小于、范围、左LIKE、右LIKE、左右LIKE）
			tableColumn.setSort(sort += 10); // 排序（升序）
			result.add(tableColumn);
		}
		return result;
	}

	/**
	 * 保存表信息，同时批量保存表的列信息
	 */
	@Transactional(rollbackFor = Exception.class)
	public void add(GenTable genTable) {
		// 一、初始化数据
		Date date = new Date();
		genTable.setCreateDate(date);
		genTable.setUpdateDate(date);
		genTable.setId(snowFlake.nextId());
		// 给列设置所属表名称
		genTable.getColumnList().forEach(s -> s.setGenTableName(genTable.getName()));

		// 二、删除之前的数据
		// 保存之前先将之前保存的表、列信息删除
		genTableDao.deleteByName(genTable.getName());
		genTableColumnDao.deleteByGenTableName(genTable.getName());

		// 三、保存表、列信息
		genTableDao.insert(genTable); // 保存表信息
		genTableColumnDao.inserts(genTable.getColumnList()); // 批量保存列信息

		// 四、保存子表信息
		if (CollectionUtil.isNotEmpty(genTable.getGenTableChilds())) {
			genTableChildDao.inserts(genTable.getGenTableChilds());
		}

		// 五、生成代码
		if (genTable.getIsCreate()) codeGenService.generatorCode(genTableDao.get(genTable));
	}

	/**
	 * 更新表信息，同时批量更新表的列信息
	 */
	@Transactional(rollbackFor = Exception.class)
	public void update(GenTable genTable) {
		// 一、初始化数据
		genTable.setUpdateDate(new Date());

		// 二、保存表信息
		genTableDao.update(genTable);

		// 三、保存列信息
		genTableColumnDao.deleteByGenTableName(genTable.getName());
		genTable.getColumnList().stream().forEach(s -> s.setGenTableName(genTable.getName()));
		genTableColumnDao.inserts(genTable.getColumnList());

		// 四、保存子表信息
		genTableChildDao.deleteByGenTableId(genTable.getId());
		if (CollectionUtil.isNotEmpty(genTable.getGenTableChilds())) {
			genTable.getGenTableChilds().forEach(s -> s.setGenTableId(genTable.getId()));
			genTableChildDao.inserts(genTable.getGenTableChilds());
		}

		// 五、生成代码
		if (genTable.getIsCreate()) codeGenService.generatorCode(genTableDao.get(genTable));
	}

	/**
	 * 根据 id 获取生成表的信息
	 */
	public GenTable get(GenTable genTable) {
		return genTableDao.get(genTable);
	}

	/**
	 * 预览
	 */
	public List<GeneratedContent> preview(GenTable genTable) {
		GenTable table = genTableDao.get(genTable);
		List<GeneratedContent> result = codeGenService.preview(table);
		return result;
	}

	/**
	 * 删除表信息，同时删除表的列信息
	 */
	@Transactional(rollbackFor = Exception.class)
	public void delByGenTableName(DelByGenTableNameVO delByGenTableNameVO) {
		genTableDao.deleteByNameList(delByGenTableNameVO.getName());
		genTableColumnDao.deleteByGenTableNameList(delByGenTableNameVO.getName());
	}

	/**
	 * 查询表信息
	 */
	public List<GenTable> findList(PageGenTableVO pageGenTableVO) {
		return genTableDao.findList(pageGenTableVO);
	}

	/**
	 * 根据表的 ids 批量生成代码
	 */
	public void createByIds(CreateByIdsVO ids) {
		List<GenTable> tableList = genTableDao.getByIds(ids.getIds());
		// 生成文件
		tableList.forEach(codeGenService::generatorCode);
	}

	/**
	 * 根据表的 ids 批量生成代码（zip）
	 */
	public byte[] createZipByIds(CreateByIdsVO ids) {
		// 根据 ids 查找表数据（同时级联查询列、子表）
		List<GenTable> tableList = genTableDao.getByIds(ids.getIds());

		ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
		ZipOutputStream zip = new ZipOutputStream(outputStream);

		tableList.forEach(s -> codeGenService.generatorCodeZip(s, zip));
		IOUtils.closeQuietly(zip);

		// 生成文件
		byte[] bytes = outputStream.toByteArray();
		return bytes;
	}
}